www.gusucode.com > VC++ IP包流量分析程序 > VC++ IP包流量分析程序/gusucode/IPanalyser/ARP.cpp

    //Download by http://www.NewXing.com
// ARP.cpp: implementation of the ARP class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "IPAnalyser.h"
#include "ARP.h"
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib, "ws2_32.lib")
#include <pcap.h>
#include <string>
#include <map>
#include <remote-ext.h>
using namespace std;

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
unsigned char* globalLocalMac;		//全局本机mac地址
pcap_if_t* globalAdapter = 0;		//当前适配器
bool nThreadSignal = false;			//活动主机线程信号
bool nIPThreadSignal = false;		//IP捕获信号
CString selectedIP;					//所选IP
int runTime;						//运行时间
map<CString, PacketInfo> infoMap;	//接收包信息
DWORD startTime;					//IP包捕获开始时间
DWORD endTime;						//IP包捕获结束时间

ARP::ARP()
{

}

ARP::~ARP()
{

}

//格式化IP地址和子网掩码地址
char* ARP::IpToStr(unsigned long ulIP)	
{							
	static char output[12][3 * 4 + 3 + 1];
	static short which;									
	unsigned char* chIP;
	chIP = (unsigned char*)&ulIP;							
	which = (which + 1 == 12 ? 0 : which + 1); 
	sprintf(output[which], "%d.%d.%d.%d", chIP[0], chIP[1], chIP[2], chIP[3]); 
	return output[which];
}

//格式化Mac地址
CString ARP::MacToStr(unsigned char* macAddress)
{							
	CString strMAC;
	strMAC.Format("%02X-%02X-%02X-%02X-%02X-%02X",macAddress[0],macAddress[1],macAddress[2],macAddress[3],macAddress[4],macAddress[5]);
	return strMAC;
}


//填充ARP包,把自己作为目的,构建一个广播ARP请求包,伪造请求来自.112.112.112
unsigned char* ARP::FillRequestARPPacket(unsigned char* sourceMAC, unsigned char* arpSourceMAC, unsigned long sourceIP, unsigned long destIP, int size)
{
    static arp_packet packet;
	//创建广播ARP包
    static const arp_packet defaultPacket = {ETH_HRD_DEFAULT, ARP_HRD_DEFAULT};
	memcpy(&packet, &defaultPacket, sizeof(defaultPacket));
    //填充源MAC地址
    memcpy(packet.eth.source_mac, sourceMAC, 6);	//ehter源MAC
    memcpy(packet.arp.sour_addr, arpSourceMAC, 6);	//arp源MAC
    packet.arp.sour_ip = sourceIP;					//源IP地址    
    packet.arp.dest_ip = destIP;					//目的IP地址
	return (unsigned char*)&packet;
}

//获取本机Mac地址
unsigned char* ARP::GetLocalMac(char *adapterName, unsigned long localIP, bool &myMacSignal)
{
	pcap_t* adapterHandle;
	char errBuff[PCAP_ERRBUF_SIZE+1];
	
	//适配器异常检查
	if((adapterHandle = pcap_open_live(adapterName, 60, 1, 100, errBuff)) == NULL)
	{
		MessageBox(NULL, "无法打开适配器!", NULL, MB_OK);
		return NULL;
	}
	struct pcap_pkthdr* header;
	const u_char* pktData;
	unsigned short arpOperation;
	static unsigned char arpSourceMAC[6];
	unsigned long arpSourceIP = 0;
	unsigned long arpDestIP = 0;
	unsigned char sourcMAC[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	
	unsigned char* packet;

	//封arp包
	packet = FillRequestARPPacket(sourcMAC, sourcMAC, SOURCE_IP, localIP, 60);
	
	int pcapnext = 0;
	//bool myMacSignal = false;
	while(!myMacSignal)
	{
		//发送arp包
		pcap_sendpacket(adapterHandle, packet, 60) ;
		Sleep(10);

		//接收arp包
		pcapnext = pcap_next_ex(adapterHandle, &header, &pktData);
		if(pcapnext == 0)
		{
			continue;
		}
		
		//获取接收的arp包信息
		memcpy(&arpOperation, pktData + 20, 2);
		memcpy(arpSourceMAC, pktData + 22, 6);
		memcpy(&arpSourceIP, pktData + 28, 4);
		memcpy(&arpDestIP, pktData + 38, 4);
		
		//收到应答包
		if(arpOperation == htons(ARP_REPLY) && arpSourceIP == localIP && arpDestIP == SOURCE_IP)
		{
			myMacSignal = true;
			pcap_close(adapterHandle);
			return arpSourceMAC;
		}
		Sleep(100);
	}
	
	pcap_close(adapterHandle);
	
	return arpSourceMAC;
}

//解析IP协议类型
char * GetProtocolType(BYTE protocolType)
{
	switch (protocolType)
	{
	case 6:
		return "TCP";
	case 17:
		return "UDP";
	default:
		return "Unknown";
		
	}
}

//arp包发送线程
UINT SendArpPacket(LPVOID pParam)
{
	pcap_addr_t* address = 0;
	unsigned long localIP = 0;
	unsigned long destIP = 0;
	unsigned long snd_tpa = 0;
	
	int netsize = 0;
	pcap_t* adapterHandle;
	char errBuff[PCAP_ERRBUF_SIZE + 1];
	if((adapterHandle = pcap_open_live(globalAdapter->name, 60, 0, 100, errBuff)) == NULL)
	{
		MessageBox(NULL, "该适配器无法打开", NULL, MB_OK);
		return 0;
	}
	
	unsigned char* requestPacket;
	ARP arp;

	//给本网卡的所有ip子网发arp报文
	for(address = globalAdapter->addresses; address; address = address->next)
	{
		if(nThreadSignal == false)
		{
			break;
		}
		
		//获取IP地址
		localIP = ((struct sockaddr_in *)address->addr)->sin_addr.s_addr;		
		if(!localIP)
		{
			continue;
		}

		//填充报文
		requestPacket = arp.FillRequestARPPacket(globalLocalMac, globalLocalMac, localIP, localIP, 60);
		
		//取子网大小
		unsigned long nlNetMask = 0;
		nlNetMask = ((struct sockaddr_in *)(address->netmask))->sin_addr.s_addr;
		netsize = ~ntohl(nlNetMask);	//子网大小255
		destIP = ntohl(localIP & nlNetMask);
		//给该IP所在子网的所有IP发送报文
		for(int i = 0; i < netsize; i++)
		{
			if(nThreadSignal == false)
			{
				break;
			}
			snd_tpa = htonl(destIP);
			memcpy(requestPacket + 38, &snd_tpa, 4);
			pcap_sendpacket(adapterHandle, requestPacket, 60);
			destIP++;
			Sleep(5);
		}
	}
	return 0;
}


//arp包接收线程
UINT ReceiveArpPacket(LPVOID pParam)
{
	pcap_t* adapterHandle;
	char errBuff[PCAP_ERRBUF_SIZE + 1];
	if((adapterHandle = pcap_open_live(globalAdapter->name, 60, 0, 100, errBuff)) == NULL)
	{
		MessageBox(NULL, "无法连接适配器!", NULL, MB_OK);
		return -1;
	}
	
	ARP arp;
	string packetInfo;
	char* filter = "ether proto\\arp";
	bpf_program fcode;
	int res;
	unsigned short operation = 0;
	unsigned char sourceMAC[6];
	unsigned long sourceIP = 0;
	unsigned long netmask = 0;
	struct pcap_pkthdr* header;
	const u_char* pktData;
	if(pcap_compile(adapterHandle, &fcode, filter, 1, (unsigned long)(0xFFFF0000)) < 0)
	{
		MessageBox(NULL, "Filter is wrong", NULL, MB_OK);
		return -1;
	}
	
	if(pcap_setfilter(adapterHandle, &fcode) < 0)
	{
		MessageBox(NULL, "Filter is not right with the Adapter!", NULL, MB_OK);
		return -1;
	}
	
	//获取报文
	while(true)
	{
		if(nThreadSignal == false)
		{
			break;
		}
		packetInfo = "";
		res = pcap_next_ex(adapterHandle, &header, &pktData);//获取报文信息
		if(!res)
		{
			continue;
		}
		memcpy(&operation, pktData + 20, 2);	//获取操作符
		memcpy(sourceMAC, pktData + 22, 6);		//获取源MAC地址
		memcpy(&sourceIP, pktData + 28, 4);		//获取源IP地址

		//格式化IP-MAC地址
		packetInfo += arp.IpToStr(sourceIP);
		packetInfo += ":";
		packetInfo += arp.MacToStr(sourceMAC);
	
		//将MAC-IP列表显示更新
		if(operation == htons(ARP_REPLY))
		{
			AfxGetApp()->m_pMainWnd->SendMessage(WM_RECEIVE, WPARAM(&packetInfo), 0);
		}
		
	}
	return 0;
}

//IP包分析线程
UINT AnaylsisPackets(LPVOID pParam)
{
	pcap_t * handle;
	//打开适配器
	char errBuff[PCAP_ERRBUF_SIZE+1];
	if((handle = pcap_open_live(
		globalAdapter->name,		//网络设备名
		65535,						//允许截获数据包的最大长度
		PCAP_OPENFLAG_PROMISCUOUS,	//混杂模式设置
		1000,						//读取数据超时时间
		errBuff))==NULL)			//错误信息
	{
		MessageBox(NULL, "不能打开适配器", NULL, MB_OK);
	}
	
	//获取子网掩码
	unsigned int netMask;	
	if(globalAdapter->addresses != NULL)
	{
		netMask = ((struct sockaddr_in *)(globalAdapter->addresses->netmask))->sin_addr.s_addr;
	}
	else
	{
		netMask = 0xffffff;//忽略子网掩码
	}
	
	//限定过滤表达式
	char packetFilter[] = "tcp or udp";	//过滤表达式

	//编译过滤器
	struct bpf_program fcode;
	if (pcap_compile(handle, &fcode, packetFilter, 1, netMask) < 0)
	{
		MessageBox(NULL, "无法编译通过滤器!", NULL, MB_OK);
		TRACE("无法编译通过滤器!%s", pcap_geterr(handle));
		return 0;
	}
	//设置过滤器
	pcap_setfilter(handle, &fcode);
	
	int res = 0;
	struct pcap_pkthdr *header;
	const u_char *pkt_data;
	DWORD nowTime;
	ARP arp;
	while(res >= 0)
	{
		res = pcap_next_ex(handle, &header, &pkt_data);
		//检查运行时间是否结束,若是则跳出循环
		nowTime = GetTickCount();	
		if(runTime != 0)
		{
			if((nowTime - startTime) >= runTime)
			{
				nIPThreadSignal = false;
				endTime = nowTime;
				break;
			}
		}
		//检查用户是否结束该线程,若是则跳出循环
		if(!nIPThreadSignal)
		{
			break;
		}
		if (res == 0)
		{
			continue;
		}
	
		
		//获取IP包内容
		IPHeader *ipHeader;
		ipHeader = (IPHeader *)(pkt_data + 14);
		//若用户选择默认地址
		bool flag = false;
		if (strcmp(LPCSTR(selectedIP), DEFAULTSETTING) == 0)
		{
		}
		//若该包发送或目的地址与用户所选IP相同,则记录该包信息
		if(strcmp(arp.IpToStr(ipHeader->sourceAddr),LPCSTR(selectedIP)) == 0 
			|| strcmp(arp.IpToStr(ipHeader->destAddr),LPCSTR(selectedIP)) == 0 
			|| strcmp(LPCSTR(selectedIP), DEFAULTSETTING) == 0)
		{
			//记录该IP包信息
			map<CString, PacketInfo>::iterator infoIterator;	
			infoIterator = infoMap.begin();
			//获取源地址、目的地址、协议类型
			CString source( inet_ntoa(*(in_addr*)&ipHeader->sourceAddr) );
			CString dest( inet_ntoa(*(in_addr*)&ipHeader->destAddr) );
			CString type( GetProtocolType(ipHeader->protocol) );
			
			//判断是udp/tcp,获取端口号
			unsigned int ip_len = (ipHeader->version & 0xf) * 4;
			unsigned short sport;
			unsigned short dport;
			if ( ipHeader->protocol == 6)//TCP
			{
				// 获得TCP首部的位置  
				TCPHeader *tcp = (TCPHeader *) ((unsigned char*)ipHeader + ip_len); 
				// 将网络字节序列转换成主机字节序列 
				sport = ntohs( tcp->sport ); //源端口号
				dport = ntohs( tcp->dport ); //目的端口号
			}
			else if(ipHeader->protocol == 17)//UDP
			{
				// 获得UDP首部的位置   
				UDPHeader *udp = (UDPHeader *) ((unsigned char*)ipHeader + ip_len); 
				// 将网络字节序列转换成主机字节序列 
				sport = ntohs( udp->sport ); //源端口号
				dport = ntohs( udp->dport ); //目的端口号
			}
			
			//设置主键

			//CString key = source + dest + (CString)sport + (CString)dport + type;
			CString str1;
			str1.Format("%d",sport);
			CString str2;
			str2.Format("%d",dport);
			
			CString key = source + dest + str1 + str2 + type;
			
			PacketInfo packetInfo;
			packetInfo.sourceIP = source;
			packetInfo.destIP = dest;
			packetInfo.sourcePort.Format("%d",sport);
			packetInfo.destPort.Format("%d",dport);
			packetInfo.protocolType = type;
			packetInfo.total = 1;
			
			infoIterator = infoMap.find(key);
			
			//插入键值
			if(infoIterator == infoMap.end())
			{
				infoMap[key] = packetInfo;
			} 
			else
			{
				infoMap[key].total++;
			}
		}
	}

	AfxGetApp()->m_pMainWnd->SendMessage(WM_ANALYSIS, WPARAM(&infoMap), 0);
	return 0;
}